package com.xueqiu.movieplaymanagersystem.utils;

import org.commonmark.Extension;
import org.commonmark.ext.gfm.tables.TableBlock;
import org.commonmark.ext.gfm.tables.TablesExtension;
import org.commonmark.ext.heading.anchor.HeadingAnchorExtension;
import org.commonmark.node.Link;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.AttributeProvider;
import org.commonmark.renderer.html.HtmlRenderer;

import java.util.*;

/**
 * @author xueqiu
 */
public class MarkdownUtils {

    /**
     * markdown格式 转换-> HTML格式
     *
     * @param markdown 数据源；markdown格式String
     * @return HTML格式String
     */
    public static String markdownToHtml(String markdown) {
        //Parser 对象，用于解析 Markdown 文本
        Parser parser = Parser.builder().build();
        //Parser 对象解析 markdown 字符串，将其转换为一个 CommonMark 的节点树，存储在 document 变量中
        Node document = parser.parse(markdown);
        /*
        使用 commonmark-ext-gfm 库中的 HtmlRenderer 类来渲染 Markdown 为 HTML，
        创建一个 HtmlRenderer 对象，用于将 CommonMark 节点树渲染为 HTML 字符串
         */
        HtmlRenderer renderer = HtmlRenderer.builder().build();
        return renderer.render(document);
    }

    /**
     * markdown格式 转换-> HTML格式；增加扩展[标题锚点，表格生成]
     *
     * @param markdown 数据源；markdown格式String
     * @return HTML格式String
     */
    public static String markdownToHtmlExtensions(String markdown) {
        /*
        Collections.singleton()返回一个只包含该对象的不可修改的集合
        在这个例子中，它创建了一个包含单个 HeadingAnchorExtension 实例的集合
        创建了一个包含 HeadingAnchorExtension 的扩展集合，用于生成标题的唯一标识符

        HeadingAnchorExtension.create() 是 commonmark 库中的一个静态方法，用于创建 HeadingAnchorExtension 的实例。
        HeadingAnchorExtension 是一个 Markdown 扩展，用于为标题生成唯一的锚点（anchor）标识符。

        当将 HeadingAnchorExtension 添加到 HtmlRenderer 的扩展列表中时，
        它会在渲染 Markdown 标题时自动为每个标题生成一个唯一的锚点标识符。
        这个锚点标识符通常用于创建标题的链接或在文档中进行跳转定位。

        通过使用 HeadingAnchorExtension.create() 方法创建 HeadingAnchorExtension 实例，
        您可以将该扩展添加到 HtmlRenderer 的扩展列表中，从而启用标题锚点的功能。
        在代码片段中，Collections.singleton(HeadingAnchorExtension.create()) 创建了一个只包含一个 HeadingAnchorExtension 实例的集合
        然后将其用于配置 HtmlRenderer 的扩展列表，以便支持标题锚点的生成。
         */
        Set<Extension> headingAnchorExtensions = Collections.singleton(HeadingAnchorExtension.create());

        /*
        Collections.singletonList() 方法接受一个对象作为参数，并返回一个只包含该对象的不可修改的列表。
        创建了一个包含 TablesExtension 的扩展列表，用于支持解析和渲染 Markdown 表格

        TablesExtension.create() 是 commonmark 库中的一个静态方法，用于创建 TablesExtension 的实例。
        TablesExtension 是一个 Markdown 扩展，用于解析和渲染 Markdown 中的表格。

        当将 TablesExtension 添加到 Parser 或 HtmlRenderer 的扩展列表中时，它会启用对 Markdown 表格的支持。
        这意味着在解析 Markdown 时，Parser 将能够正确解析表格语法，并将其转换为相应的数据结构。
        而在渲染 Markdown 为 HTML 时，HtmlRenderer 将能够将表格转换为适当的 HTML 标记。

        通过使用 TablesExtension.create() 方法创建 TablesExtension 实例，
        您可以将该扩展添加到 Parser 或 HtmlRenderer 的扩展列表中，从而启用对 Markdown 表格的解析和渲染功能。
        在代码片段中，Collections.singletonList(TablesExtension.create()) 创建了一个只包含一个 TablesExtension 实例的列表，
        然后将其用于配置 Parser 或 HtmlRenderer 的扩展列表，以便支持表格的解析和渲染。
         */
        List<Extension> tableExtension = Collections.singletonList(TablesExtension.create());

        //创建了 Parser 对象，通过使用 tableExtension 配置扩展列表来解析 Markdown 文本，生成解析树节点的 document
        Parser parser = Parser.builder()
                .extensions(tableExtension)
                .build();
        Node document = parser.parse(markdown);
        /*
        创建了 HtmlRenderer 对象，通过使用 headingAnchorExtensions 和 tableExtension 配置扩展列表，
        以及自定义的 CustomAttributeProvider 来提供 HTML 元素的自定义属性

        使用 commonmark-ext-gfm 库中的 HtmlRenderer 类来渲染 Markdown 为 HTML，并自定义生成的 HTML 标签的属性
         */
        HtmlRenderer renderer = HtmlRenderer.builder()
                .extensions(headingAnchorExtensions)
                .extensions(tableExtension)
                //设置属性提供程序工厂。属性提供程序用于自定义生成的 HTML 标签的属性。
                .attributeProviderFactory(element -> new CustomAttributeProvider())
                .build();
        return renderer.render(document);
    }

    /**
     * 在 CustomAttributeProvider 类中，setAttributes() 方法被重写
     * 重写原因：方便自定义生成的 HTML 标签的属性进行构建
     * 重写规则：
     * 检查节点类型，如果是 Link 类型（表示 <a> 标签），则将 target 属性设置为 _blank，以使链接在新窗口中打开
     * 检查节点类型，如果是 TableBlock 类型（表示表格块），则将 class 属性设置为 "ui celled table"，以应用自定义的 CSS 类
     */
    static class CustomAttributeProvider implements AttributeProvider {
        /**
         * 在 CustomAttributeProvider 类中，setAttributes() 方法被重写
         * 重写原因：方便自定义生成的 HTML 标签的属性进行构建
         * 重写规则：
         * 检查节点类型，如果是 Link 类型（表示 <a> 标签），则将 target 属性设置为 _blank，以使链接在新窗口中打开
         * 检查节点类型，如果是 TableBlock 类型（表示表格块），则将 class 属性设置为 "ui celled table"，以应用自定义的 CSS 类
         *
         * @param node       标签节点
         * @param tagName    标签名称
         * @param attributes 标签细节
         */
        @Override
        public void setAttributes(Node node, String tagName, Map<String, String> attributes) {
            //改变<a>标签的target属性为_blank
            if (node instanceof Link) {
                attributes.put("target", "_blank");
            }
            //改变<table>标签的class属性为ui celled table
            if (node instanceof TableBlock) {
                attributes.put("class", "ui celled table");
            }
        }
    }
}
